//
//  AirportSensor.m
//  Pennyworth
//
//  Created by Chris Karr on 12/24/07.
//  Copyright 2007 Chris J. Karr. All rights reserved.
//

#import "AirportSensor.h"
#import "Context.h"
#import "Apple80211.h"
#import "SensorsController.h"

#define SENSOR_NAME @"Airport Networks"

// #define AIRPORT_TOOL @"/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport"

#define ALWAYS_SCAN @"Always_Scan"
#define SCAN_FOR_NETWORKS @"WiFi_Scan"

static NSString * macToString (const UInt8 * mac)
{
	return [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]];
}

@implementation AirportSensor

/*+ (id) airportTool:(NSArray *) args
{
    NSTask * task = [NSTask new];
    NSData * output;
	
    [task setLaunchPath:AIRPORT_TOOL];
    [task setArguments:[args arrayByAddingObject:@"--xml"]];
    [task setStandardOutput:[NSPipe pipe]];
    [task setStandardError:[task standardOutput]];
	
    @synchronized (AIRPORT_TOOL)
    {
        [task launch];
        output = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
    }
    
    [task release];
	
	id plist = nil;
		    
    if (output && [output length] > 0)
    {
        NSString* error;
     
        plist = [NSPropertyListSerialization propertyListFromData:output mutabilityOption:NSPropertyListImmutable 
					format:NULL errorDescription:&error];
        
        if (error)
			return [[[NSString alloc] initWithBytes:[output bytes] length:[output length] encoding:NSUTF8StringEncoding] autorelease];
    }
    
    return plist;
}

+ (NSArray *) availableNetworks
{
	return [AirportSensor airportTool:[NSArray arrayWithObject:@"-s"]];
}

+ (NSDictionary *) currentNetwork
{
	NSString * currentString = [AirportSensor airportTool:[NSArray arrayWithObject:@"-I"]];
	
	NSString * ssid = nil;
	NSString * bssid = nil;
	
	NSString * rssi = nil;
	
	NSArray * lines = [currentString componentsSeparatedByString:@"\n"];
	NSEnumerator * iter = [lines objectEnumerator];
	NSString * line = nil;
	
	while ((line = [iter nextObject]) != nil)
	{
		if ([line rangeOfString:@"BSSID"].location != NSNotFound)
			bssid = [line substringFromIndex:17];
		else if ([line rangeOfString:@"SSID"].location != NSNotFound)
			ssid = [line substringFromIndex:17];
		else if ([line rangeOfString:@"agrCtlRSSI"].location != NSNotFound)
			rssi = [line substringFromIndex:17];
	}

	if ([ssid length] > 0)
	{
		NSMutableDictionary * dict = [NSMutableDictionary dictionary];
		[dict setValue:bssid forKey:@"BSSID"];
		[dict setValue:ssid forKey:@"SSID"];
		[dict setValue:rssi forKey:@"RSSI"];
	
		return dict;
	}
	else
		return nil;
} */
	
- (void) update: (NSTimer *) theTimer
{
	if (![[SensorsController sharedController] canFire:SENSOR_NAME])
	{
		NSMutableDictionary * note = [NSMutableDictionary dictionary];
		[note setValue:@"Current Wireless Network" forKey:OBSERVATION_SENSOR];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];

		[note setValue:@"Current Wireless Signal Level" forKey:OBSERVATION_SENSOR];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];
		
		[note setValue:@"Available Wireless Networks" forKey:OBSERVATION_SENSOR];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];

		return;
	}	
	
	if (!WirelessIsAvailable ())
		return;
	
	WirelessContextPtr wctxt = 0;
	WirelessInfo info;
	BOOL scan = YES;
	WIErr err;

	if ((err = WirelessAttach (&wctxt, 0)) != noErr) 
	{
		NSLog (@"%@ >> WirelessAttached failed with error code 0x%08x", [self class], err);

		return;
	}

	if ((WirelessGetInfo (wctxt, &info) == noErr) && (info.power > 0) && (info.link_qual > 0)) 
	{
		NSString * ssid = [NSString stringWithCString:(const char *) info.name encoding:NSISOLatin1StringEncoding];
		NSString * mac = macToString (info.macAddress);

		NSString * desc = [NSString stringWithFormat:@"%@ (%@)", ssid, mac];
		
		NSMutableDictionary * note = [NSMutableDictionary dictionary];
		[note setValue:@"Current Wireless Network" forKey:OBSERVATION_SENSOR];
		[note setValue:desc forKey:OBSERVATION_OBSERVATION];
		[note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];

		/* note = [NSMutableDictionary dictionary];
		[note setValue:@"Current Wireless Link Quality" forKey:OBSERVATION_SENSOR];
		[note setValue:[NSNumber numberWithUnsignedShort:info.link_qual] forKey:OBSERVATION_OBSERVATION];
		[note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; */

		note = [NSMutableDictionary dictionary];
		[note setValue:@"Current Wireless Signal Level" forKey:OBSERVATION_SENSOR];
		[note setValue:[NSNumber numberWithFloat:(100 - (((pow (2, 16)) - 1) - ((float) info.signal)))] forKey:OBSERVATION_OBSERVATION];
		[note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];
		
		scan = NO;
	}

	NSObject * defaultsScan = [[NSUserDefaults standardUserDefaults] objectForKey:ALWAYS_SCAN];
	
	if (defaultsScan != nil && [[NSUserDefaults standardUserDefaults] boolForKey:ALWAYS_SCAN])
		scan = YES;
	
	if (scan)
	{
		NSArray * list = nil;

		if (WirelessScan (wctxt, (CFArrayRef *) &list, 0) != noErr)
		{

		}
		else if (!list) 
		{

		}
		else
		{
			NSMutableArray * networks = [NSMutableArray array];
		
			NSData * data;

			for (data in list)
			{
				const WirelessNetworkInfo * ap;
				ap = (const WirelessNetworkInfo *) [data bytes];
			
				NSString * ssid = [NSString stringWithCString:(const char *) ap->name encoding:NSISOLatin1StringEncoding];
				NSString * mac = macToString (ap->macAddress);
		
				NSString * desc = [NSString stringWithFormat:@"%@ (%@)", ssid, mac];
			
				[networks addObject:desc];
			}
		
			[networks sortUsingSelector:@selector(compare:)];
		
			NSMutableDictionary * note = [NSMutableDictionary dictionary];
		
			[note setValue:@"Available Wireless Networks" forKey:OBSERVATION_SENSOR];
			[note setValue:networks forKey:OBSERVATION_OBSERVATION];
			[note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN];
		
			[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];
		}
	}
	
	WirelessDetach (wctxt);
}

- (void) awakeFromNib
{
	[[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain];
	
	[self update:nil];
	[[SensorsController sharedController] addSensor:SENSOR_NAME];
}


@end
